#include "TcpConnection.h"
#include "Buffer.h"
#include "Channel.h"
#include "Logger.h"
#include "TaskQueue.h"

namespace GiSo {

// 构造函数
TcpConnection::TcpConnection(std::unique_ptr<Channel> channel,TaskQueue::Ptr taskQueue)
    : m_TaskQueue(taskQueue)
{
    if(!channel){
        GS_ERROR("TcpConnection::TcpConnection - channel is nullptr");
        throw std::invalid_argument("TcpConnection requires a valid Channel object, nullptr provided.");
    }
    m_Channel = std::move(channel);
    // 设置 Channel 的回调函数
    m_Channel->SetReadCallback( [this] { if(m_Running)HandleRead();});
    m_Channel->SetWriteCallback([this] { if(m_Running)HandleWrite();});
    m_Channel->SetCloseCallback([this] { if(m_Running)HandleClose();});     // 关闭有两种，一种是对端关闭，一种是自己关闭，这里是对端关闭
    m_Channel->SetErrorCallback([this] { if(m_Running)HandleError();});
    EnableReading();    // 默认启动读事件，关闭写事件
}

// 析构函数
TcpConnection::~TcpConnection() {
    if(m_Running.exchange(false)){
        m_Channel->Close();
    }
    GS_INFO("TcpConnection::~TcpConnection - fd={0}", m_Channel->GetFd());
}


bool TcpConnection::Send(const std::string& data) {
    return Send(data.data(), data.size());
}

bool TcpConnection::Send(const std::vector<char>& data) {
    return Send(data.data(), data.size());
}

bool TcpConnection::Send(const void* data, size_t len) {
    if(len==0)
        return true;
    if(m_Writing==false){
        // 尝试能否直接发送数据
        int n = m_Channel->Write(data,len);
        auto saveErrno = errno;
        if(n<0){
            if(saveErrno==EAGAIN || saveErrno==EWOULDBLOCK){
                // 缓冲区满了，不能直接发送，需要等待下一次写事件
                GS_TRACE("TcpConnection::Send - fd={0} - EAGAIN or EWOULDBLOCK", m_Channel->GetFd());
                return false;
            }
            else{
                GS_ERROR("TcpConnection::Send - fd={0} - write error: {1}", m_Channel->GetFd(), strerror(saveErrno));
                HandleClose();
                return false;
            }
        }
        else if(n==len){
            // 发送成功
            GS_TRACE("TcpConnection::Send - fd={0} - send success", m_Channel->GetFd());
            return true;
        }
        else{
            // 发送不完全,剩下的交给主线程的写事件处理（工作线程只尝试发送一次）
            GS_TRACE("TcpConnection::Send - fd={0} - send partial", m_Channel->GetFd());
            return m_OutputBuffer.Append(static_cast<const char*>(data)+n,len-n);
        }
    }
    EnableWriting();
    return m_OutputBuffer.Append(data,len);
}

// 主动关闭连接（哪个线程都有可能）
void TcpConnection::Close() {
    HandleClose();
}

// 处理读事件 （在主线程执行）
void TcpConnection::HandleRead() {
    auto callBack = [weakPtr = std::weak_ptr<TcpConnection>(shared_from_this())](){
        auto ptr = weakPtr.lock();
        if(!ptr||!ptr->m_Running||!ptr->m_Reading)return;
        char buf[2048];
        int total = 0;
        while(true){
            int n = ptr->m_Channel->Read(buf,2048);
            auto saveErrno = errno;
            if(n==0&&total<=0){
                GS_INFO("TcpConnection::HandleRead - fd={0} - peer closed", ptr->m_Channel->GetFd());
                ptr->HandleClose();
                return;
            }
            else if(n<0){
                if(saveErrno==EAGAIN || saveErrno==EWOULDBLOCK){
                    GS_TRACE("TcpConnection::HandleRead - fd={0} - EAGAIN or EWOULDBLOCK", ptr->m_Channel->GetFd());
                    return;
                }
                else{
                    GS_ERROR("TcpConnection::HandleRead - fd={0} - read error: {1}", ptr->m_Channel->GetFd(), strerror(saveErrno));
                    ptr->HandleClose();
                    return;
                }
            }

            if(n>0){
                total += n;
                bool res = ptr->m_InputBuffer.Append(buf,n);
                if(!res){
                    GS_ERROR("TcpConnection::HandleRead - fd={0} append data to buffer error", ptr->m_Channel->GetFd());
                    ptr->m_InputBuffer.Clear();
                }
            }
            if(n!=2048)
                break;
        }
        if(ptr->m_ReadCallback&&ptr->m_Running){
            ptr->m_ReadCallback(ptr,ptr->m_InputBuffer);
        }
    };
    m_TaskQueue->PushBack(callBack);
}

// 处理写事件（写的操作在worker线程，写完的回调在worker线程,）
void TcpConnection::HandleWrite() {
    // 检查写buffer是否为空，如果为空则直接返回
    if(m_OutputBuffer.ReadableBytes()==0){
        DisableWriting();
        return;
    }
    m_OutputBuffer.AssignToString(m_WriteData);
    int n = m_Channel->Write(m_WriteData.data(),m_WriteData.size());
    auto saveErrno = errno;
    if(n<0){
        // 写错误-根据错误类型处理
        if(saveErrno==EAGAIN || saveErrno==EWOULDBLOCK){
            GS_TRACE("TcpConnection::HandleWrite - fd={0} - EAGAIN or EWOULDBLOCK", m_Channel->GetFd());
            return;
        }
        else{
            GS_ERROR("TcpConnection::HandleWrite - fd={0} - write error: {1}", m_Channel->GetFd(), strerror(saveErrno));
            HandleClose();
            return;
        }
    }
    else if(n==0){
        // 对端关闭连接
        GS_ERROR("TcpConnection::HandleWrite - fd={0} - write error: {1}", m_Channel->GetFd(), strerror(saveErrno));
        HandleClose();
        return;
    }
    else{
        // 写完了
        m_OutputBuffer.PopFront(n);
        if(m_OutputBuffer.ReadableBytes()==0){
            // 写完了，通知上层
            DisableWriting();
            if(m_WriteCompleteCallback){
                m_TaskQueue->PushBack([weakPtr = std::weak_ptr<TcpConnection>(shared_from_this())](){
                    auto ptr = weakPtr.lock();
                    if(ptr&&ptr->m_Running&&ptr->m_WriteCompleteCallback&&ptr->m_Writing){
                        ptr->m_WriteCompleteCallback(ptr);
                    }
                });
            }
        }
    }
}

void TcpConnection::HandleClose() {
    if(m_Running.exchange(false)){
        m_Channel->Remove();    // 从poller中移除,但是没有关闭fd，fd的关闭是在Channel析构的时候
        if(m_CloseCallback)
            m_CloseCallback(shared_from_this());
        if(m_RemoveFromContainerCallback)
            m_RemoveFromContainerCallback(shared_from_this());
    }
}

// 处理错误事件
void TcpConnection::HandleError() {
    GS_ERROR("TcpConnection::HandleError - fd={}", m_Channel->GetFd());
    HandleClose();
}

}